package controller;

import Enums.Image_Line_State;
import Enums.State;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.Date;
import javax.swing.JFileChooser;
import javax.swing.JOptionPane;
import javax.swing.SwingWorker;
import model.Model_Config;
import tools.FileFilterData;
import tools.Data;
import org.jgap.*;

/**
 * Klasse, die sich um das Laden und Speichern von Prozessfortschritten kuemmert.
 *
 */
public class SaveLoadData {

    String dir = ".";
    private static SaveLoadData instance;

    /**
     * Gibt die einzige Instanz von SaveLoadData zurueck
     * (bzw. erzeugt diesen am Anfang)
     * @return das einzige SaveLoadData Objekt
     */
    public synchronized static SaveLoadData getInstance() {
        if (instance == null) {
            instance = new SaveLoadData();
        }
        return instance;
    }

    private SaveLoadData() {
    }

    /**
     * Es wird ein Object Data,
     * in den eingegebenen file gespeichert.
     *
     * Data enthaelt folgende attribute:
     * SerializableBufferedImage serializable_image_original;
     * SerializableBufferedImage serializable_image_line;
     * Model_Config config;
     * Document xml;
     *
     * Und am ende wird Image_Line_State auf saved gesetzt,
     * @param file
     * @throws Exception
     */
    private void saveData(FileOutputStream file, String path) throws Exception {
        ObjectOutputStream o = new ObjectOutputStream(file);

        /**
         * Data erzeugen,
         * alle informationen sind nun gespeichert
         */
        Data data = new Data(path);

        /*
         * data speichern
         */
        o.writeObject((Object) data);

        o.close();

        Controller.getInstance().setLineState(Image_Line_State.saved);
        Controller.getInstance().setLogMessage("Datei gespeichert.\n");
    }

    /**
     * Es wird ein Filechooser erzeugt, mit dessen hilfe man den Ort auswaehlen
     * kann, wo mann speichern moechte.
     * Wenn der user ein "filename" eingibt, wird dies dann ueberprueft
     * ob es schon existiert. Dann wird die Methode saveData() aufgerufen,
     * mit dessen hilfe schließlich ein gku-Datei erzeugt und gespeichert wird.
     *
     */
    public boolean save() {

        JFileChooser fileSaver = new JFileChooser(dir);
        String path = "";
        boolean done = false;
        File file;
        fileSaver.setFileFilter(FileFilterData.getInstance());
        String endung = FileFilterData.getInstance().getFormatOfData();
        try {
            while (!done) {
                if (fileSaver.showSaveDialog(null) == JFileChooser.CANCEL_OPTION) {
                    done = true;
                    return false;
                }
                dir = fileSaver.getCurrentDirectory().getCanonicalPath();

                path = fileSaver.getSelectedFile().getCanonicalPath();
                file = fileSaver.getSelectedFile();
                File f2 = new File(file.getCanonicalFile() + endung);

                if (file.exists() || f2.exists()) {
                    int confirm = JOptionPane.showConfirmDialog(fileSaver,
                            file.getName() + " ist bereits vorhanden, überschreiben?",
                            "Datei existiert bereits", JOptionPane.YES_NO_OPTION,
                            JOptionPane.INFORMATION_MESSAGE);
                    switch (confirm) {
                        case JOptionPane.NO_OPTION:
                            break;
                        case JOptionPane.YES_OPTION:
                            done = true;
                            path = file.getCanonicalPath();

                            String end = FileFilterData.getInstance().getEnd(file);
                            if (end == "") {
                                path += endung;
                            }

                            break;
                    }
                }
                else {
                    path += endung;
                    done = true;
                }
            }
            file = new File(path);
            file.setLastModified(new Date().getTime());
            FileOutputStream fos = new FileOutputStream(file.getCanonicalPath());
            saveData(fos, path);
            return true;

        }
        catch (Exception ex) {
            JOptionPane.showMessageDialog(null,
                    "Es konnte nicht gespeichert werden\n" + ex.getMessage(),
                    "Fehler beim Speichern", JOptionPane.ERROR_MESSAGE);
        }
        catch (StackOverflowError vError) {
            JOptionPane.showMessageDialog(null, "Speicherfehler\n" + vError.getMessage(), "Speicher Fehler", JOptionPane.ERROR_MESSAGE);
        }

        return false;
    }

    /**
     * Das eingegebenen File wird geladen.
     * Daraus werden die Daten entnommen und an ihre richtigen Klassen weitergegeben.
     * 
     * Das Strichbild und das originalBild werden nach erfolgreiches Laden gezeichnet.
     *
     * Dann werden Image_Line_State auf saved, und State auf waiting gesetzt.
     *
     * wenn fehler beim laden ergibt, dann werden die einstellungen auf State.nothing gesetzt
     * @param file
     */
    private void loadData(FileInputStream file, String path) throws Exception {
        ObjectInputStream o = new ObjectInputStream(file);
        Data data = (Data) o.readObject();
        o.close();

        //originalbild laden und zeigen
        BufferedImage bufferedImageOriginal = data.getBufferedImage_original();
        Controller.getInstance().setImage_original(bufferedImageOriginal);
        Controller.getInstance().setMaske(data.getMaske());

        //image_line initialisieren
        //setzt alles was mit der Evolution zusammenhaengt auf Anfangswerte zurueck
        Controller.getInstance().init_image_Line();

        //Model_Config entnehmen:
        Model_Config config = data.getConfig();

        //config an Controller geben
        Controller.getInstance().changeConfig(config);

        /**
         * genotype laden
         */
        Genotype genotype = data.getGenotype(path.substring(0, path.length() - 3) + "xml");
        Controller.getInstance().setGenotype(genotype);

        /*
         * image_line zeichnen
         */
        BufferedImage img = data.getBufferedImage_line();
        Controller.getInstance().getImage_Line().setFittestImage(img);

        /**
         * status setzen
         */
        Controller.getInstance().set_Fresh_loadedProcess(true);
        Controller.getInstance().setState(State.waiting);
        Controller.getInstance().setLineState(Image_Line_State.saved);
        Controller.getInstance().setLogMessage("Datei geladen.\n");
    }

    /**
     * Es wird ein filechooser angezeigt, mit dem der user ein datei, von typ gku aussuchen kann.
     * Dann wird die datei mit hilfe loadData(file) geoeffnet
     *
     */
    public void loadData() {

        new SwingWorker() {

            private int reval;
            private JFileChooser chooser;

            {
                try {
                    chooser = new JFileChooser(".");
                    chooser.setFileFilter(FileFilterData.getInstance());
                    reval = chooser.showOpenDialog(null);

                }
                catch (Exception ex) {
                    JOptionPane.showMessageDialog(null, ex.getMessage() + "JFileChooser-Fehler", "ERROR", JOptionPane.ERROR_MESSAGE);
                }
            }

            @Override
            protected Object doInBackground() {
                try {
                    if (reval == JFileChooser.APPROVE_OPTION) {
                        File file = chooser.getSelectedFile();
                        FileInputStream fileInput = new FileInputStream(file.getAbsoluteFile());
                        loadData(fileInput, file.getCanonicalPath());
                        return null;
                    }
                }
                catch (Exception ex2) {
                    JOptionPane.showMessageDialog(null, "Datei ist beschädigt oder nicht komplett!\n"
                            + ex2.getMessage(),
                            "Fehler beim Laden", JOptionPane.ERROR_MESSAGE);
                }
                Controller.getInstance().setState(State.nothing);
                return null;
            }
        }.execute();
    }
}
